package com.wtpaint.lib.glide.load.model;

import android.support.annotation.NonNull;

import java.util.ArrayList;
import java.util.List;

public class ModelLoaderRegistry {

    private List<Entry<?, ?>> entries = new ArrayList<>();

    /**
     * 注册loader
     *
     * @param modelClass 数据来源
     * @param dataClass  数据转换后的类型  加载后的类型
     * @param factory    创建ModelLoader工厂
     * @param <Model>
     * @param <Data>
     */
    public synchronized <Model, Data> void add(Class<Model> modelClass, Class<Data> dataClass, ModelLoader.ModelLoaderFactory factory) {
        entries.add(new Entry<>(modelClass, dataClass, factory));
    }

    /**
     * 获得对应 的modelLoader
     *
     * @param modelClass
     * @param inputStreamClass
     * @return
     */
    public <Model, Data> ModelLoader<Model, Data> build(Class<Model> modelClass, Class<Data> inputStreamClass) {

        List<ModelLoader<Model, Data>> loaders = new ArrayList<>();
        for (Entry<?, ?> entry : entries) {
            //
            if (entry.handles(modelClass, inputStreamClass)) {
                loaders.add(entry.factory.build(this));
            }
        }
        if (loaders.size() > 1) {
            return new MultiModelLoader<>(loaders);
        } else if (loaders.size() == 1) {
            return loaders.get(0);
        }
        throw new RuntimeException("No match model");
    }

    public <Model> List<ModelLoader<Model, ?>> getModelLoaders(Class<Model> modelClass) {
        List<ModelLoader<Model, ?>> modelLoaders = new ArrayList<>();
        for (Entry<?, ?> entry : entries) {
            if (entry.handles(modelClass)) {
                modelLoaders.add((ModelLoader<Model, ?>) entry.factory.build(this));
            }
        }
        return modelLoaders;
    }

    private static class Entry<Model, Data> {
        Class<Model> modelClass;
        Class<Data> dataClass;
        ModelLoader.ModelLoaderFactory factory;


        public Entry(Class<Model> modelClass, Class<Data> dataClass, ModelLoader.ModelLoaderFactory factory) {
            this.modelClass = modelClass;
            this.dataClass = dataClass;
            this.factory = factory;
        }

        public boolean handles(Class<?> modelClass, Class<?> dataClass) {
            //isAssignableFrom 参数是调用者是否同一个模型或者是子类
            return this.modelClass.isAssignableFrom(modelClass) && this.dataClass.isAssignableFrom(dataClass);
        }

        public boolean handles(@NonNull Class<?> modelClass) {
            return this.modelClass.isAssignableFrom(modelClass);
        }
    }


}
